using System;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Globalization;
using System.Linq;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Security;
using DotNetNuke.Security.Permissions;
using DotNetNuke.Services.Exceptions;
using System.Web.UI;
using System.Web.UI.WebControls;
using DotNetNuke.Services.FileSystem;
using DotNetNuke.Services.Localization;
using System.IO;

namespace HeroldIT.Dnn.Modules.News.Views
{
    public class NewsCoreSettings : ModuleSettingsBase, INewsCoreSettingsProvider
    {
        #region static methods

        /// <summary>
        /// Ensures that the given string <paramref name="s"/> ends with a slash.
        /// </summary>
        /// <param name="s">The string to check.</param>
        /// <returns>The given string <paramref name="s"/> with a trailing slash.</returns>
        protected static string EnsureTrailingSlash(string s)
        {
            if (!s.EndsWith("/", StringComparison.Ordinal))
            {
                return s + "/";
            }
            return s;
        }

        #endregion

        #region control fields

        protected ListControl lstDefaultListTabId;
        protected ListControl lstDefaultDetailTabId;
        protected ListControl lstDefaultLocale;
        protected ICheckBoxControl chkShowOnlyNewsForSelectedLocale;
        protected ITextControl txtTeaserImageFolder;
        protected ITextControl txtMaxTeaserImageWidth;
        protected ITextControl txtMaxTeaserImageHeight;
        protected ITextControl txtTeaserImageMatte;
        protected ITextControl txtTeaserImageQuality;
        protected ICheckBoxControl chkResizeTeaserImages;
        protected ITextControl txtDetailImageFolder;
        protected ITextControl txtMaxDetailImageWidth;
        protected ITextControl txtMaxDetailImageHeight;
        protected ITextControl txtDetailImageMatte;
        protected ITextControl txtDetailImageQuality;
        protected ICheckBoxControl chkResizeDetailImages;
        protected ITextControl txtMaxCurrentItems;
        protected ICheckBoxControl chkUseDetailImageForTeaserDefault;
        protected ICheckBoxControl chkShowDisabledLanguages;
        protected ITextControl txtMaxImagesToUse;

        #endregion

        #region properties

        private NewsController controller;

        protected NewsController Controller
        {
            get
            {
                if (null == this.controller)
                {
                    this.controller = new NewsController(this);
                }
                return this.controller;
            }
        }

        #endregion

        #region page lifecycle

        protected override void OnInit(EventArgs e)
        {
            var tabs = Globals.GetPortalTabs(this.PortalSettings.DesktopTabs, false, true, false, false).Cast<TabInfo>().Where(tab => PortalSecurity.IsInRoles(tab.AuthorizedRoles));
            string stayOnThisTab = this.GetString("liStayOnThisTab.Text", "<Stay on this tab>");
            if (null != this.lstDefaultListTabId)
            {
                this.lstDefaultListTabId.DataSource = tabs;
                this.lstDefaultListTabId.DataTextField = "TabName";
                this.lstDefaultListTabId.DataValueField = "TabID";
                this.lstDefaultListTabId.DataBind();
                this.lstDefaultListTabId.Items.Insert(0, new ListItem(stayOnThisTab, "-1"));
            }
            if (null != this.lstDefaultDetailTabId)
            {
                this.lstDefaultDetailTabId.DataSource = tabs;
                this.lstDefaultDetailTabId.DataTextField = "TabName";
                this.lstDefaultDetailTabId.DataValueField = "TabID";
                this.lstDefaultDetailTabId.DataBind();
                this.lstDefaultDetailTabId.Items.Insert(0, new ListItem(stayOnThisTab, "-1"));
            }
            if (null != this.lstDefaultLocale)
            {
                LocaleCollection locales = Localization.GetEnabledLocales();
                this.lstDefaultLocale.DataSource = locales.AllKeys;
                this.lstDefaultLocale.DataBind();
            }

            base.OnInit(e);
        }

        #endregion

        #region methods

        /// <summary>
        /// Loads the module's settings into the given controls.
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public override void LoadSettings()
        {
            try
            {
                if (!this.Page.IsPostBack)
                {
                    if (null != this.lstDefaultListTabId)
                    {
                        this.lstDefaultListTabId.SelectedValue = this.GetDefaultListTabId().ToString(CultureInfo.InvariantCulture);
                    }
                    if (null != this.lstDefaultDetailTabId)
                    {
                        this.lstDefaultDetailTabId.SelectedValue = this.GetDefaultDetailTabId().ToString(CultureInfo.InvariantCulture);
                    }
                    if (null != this.lstDefaultLocale)
                    {
                        this.lstDefaultLocale.SelectedValue = this.GetDefaultLocale();
                    }
                    if (null != this.chkShowOnlyNewsForSelectedLocale)
                    {
                        this.chkShowOnlyNewsForSelectedLocale.Checked = this.GetDefaultShowOnlyNewsForSelectedLocale();
                    }
                    if (null != this.txtTeaserImageFolder)
                    {
                        this.txtTeaserImageFolder.Text = this.GetTeaserImageFolder();
                    }
                    if (null != this.txtMaxTeaserImageWidth)
                    {
                        this.txtMaxTeaserImageWidth.Text = this.GetMaxTeaserImageWidth().ToString(CultureInfo.InvariantCulture);
                    }
                    if (null != this.txtMaxTeaserImageHeight)
                    {
                        this.txtMaxTeaserImageHeight.Text =
                            this.GetMaxTeaserImageHeight().ToString(CultureInfo.InvariantCulture);
                    }
                    if (null != this.txtTeaserImageMatte)
                    {
                        this.txtTeaserImageMatte.Text = this.GetTeaserImageMatte();
                    }
                    if (null != this.txtTeaserImageQuality)
                    {
                        this.txtTeaserImageQuality.Text =
                            this.GetTeaserImageQuality().ToString(CultureInfo.InvariantCulture);
                    }
                    if (null != this.chkResizeTeaserImages)
                    {
                        this.chkResizeTeaserImages.Checked = true;
                    }
                    if (null != this.txtDetailImageFolder)
                    {
                        this.txtDetailImageFolder.Text = this.GetDetailImageFolder();
                    }
                    if (null != this.txtMaxDetailImageWidth)
                    {
                        this.txtMaxDetailImageWidth.Text =
                            this.GetMaxDetailImageWidth().ToString(CultureInfo.InvariantCulture);
                    }
                    if (null != this.txtMaxDetailImageHeight)
                    {
                        this.txtMaxDetailImageHeight.Text =
                            this.GetMaxDetailImageHeight().ToString(CultureInfo.InvariantCulture);
                    }
                    if (null != this.txtDetailImageMatte)
                    {
                        this.txtDetailImageMatte.Text = this.GetDetailImageMatte();
                    }
                    if (null != this.txtDetailImageQuality)
                    {
                        this.txtDetailImageQuality.Text =
                            this.GetDetailImageQuality().ToString(CultureInfo.InvariantCulture);
                    }
                    if (null != this.chkResizeDetailImages)
                    {
                        this.chkResizeDetailImages.Checked = true;
                    }
                    if (null != this.txtMaxCurrentItems)
                    {
                        this.txtMaxCurrentItems.Text = this.GetMaxCurrentItems().ToString(CultureInfo.CurrentUICulture);
                    }
                    if (null != this.chkUseDetailImageForTeaserDefault)
                    {
                        this.chkUseDetailImageForTeaserDefault.Checked = this.GetUseDetailImageForTeaserDefault();
                    }
                    if (null != this.chkShowDisabledLanguages)
                    {
                        this.chkShowDisabledLanguages.Checked = this.GetShowDisabledLanguages();
                    }
                    if (null != this.txtMaxImagesToUse)
                    {
                        this.txtMaxImagesToUse.Text = this.GetMaxImagesToUse().ToString(CultureInfo.CurrentUICulture);
                    }
                }
            }
            catch (Exception exc) //Module failed to load
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }

        /// <summary>
        /// Updates the module's settings from the given controls.
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public override void UpdateSettings()
        {
            try
            {
                if (null != this.lstDefaultListTabId)
                {
                    int tabId;
                    if (int.TryParse(this.lstDefaultListTabId.SelectedValue, NumberStyles.None,
                                     CultureInfo.InvariantCulture, out tabId))
                    {
                        this.SetDefaultListTabId(tabId);
                    }
                }
                if (null != this.lstDefaultDetailTabId)
                {
                    int tabId;
                    if (int.TryParse(this.lstDefaultDetailTabId.SelectedValue, NumberStyles.None,
                                     CultureInfo.InvariantCulture, out tabId))
                    {
                        this.SetDefaultDetailTabId(tabId);
                    }
                }
                if (null != this.lstDefaultLocale)
                {
                    this.SetDefaultLocale(this.lstDefaultLocale.SelectedValue);
                }
                if (null != this.chkShowOnlyNewsForSelectedLocale)
                {
                    this.SetDefaultShowOnlyNewsForSelectedLocale(this.chkShowOnlyNewsForSelectedLocale.Checked);
                }
                if (null != this.txtTeaserImageFolder)
                {
                    this.SetTeaserImageFolder(this.txtTeaserImageFolder.Text);
                }
                int prevTeaserWidth = this.GetMaxTeaserImageWidth();
                int prevTeaserHeight = this.GetMaxTeaserImageHeight();
                int newTeaserWidth = prevTeaserWidth;
                int newTeaserHeight = prevTeaserHeight;
                if (null != this.txtMaxTeaserImageWidth)
                {
                    int width;
                    if (int.TryParse(this.txtMaxTeaserImageWidth.Text, NumberStyles.Integer,
                                     CultureInfo.InvariantCulture, out width))
                    {
                        this.SetMaxTeaserImageWidth(width);
                        newTeaserWidth = width;
                    }
                }
                if (null != this.txtMaxTeaserImageHeight)
                {
                    int height;
                    if (int.TryParse(this.txtMaxTeaserImageHeight.Text, NumberStyles.Integer,
                                     CultureInfo.InvariantCulture, out height))
                    {
                        this.SetMaxTeaserImageHeight(height);
                        newTeaserHeight = height;
                    }
                }
                if (null != this.txtTeaserImageMatte)
                {
                    try
                    {
                        ColorTranslator.FromHtml(this.txtTeaserImageMatte.Text);
                        this.SetTeaserImageMatte(this.txtTeaserImageMatte.Text);
                    }
                    catch (Exception e)
                    {
                        Exceptions.LogException(e);
                    }
                }
                if (null != this.txtTeaserImageQuality)
                {
                    long quality;
                    if (long.TryParse(this.txtTeaserImageQuality.Text, NumberStyles.Integer,
                                      CultureInfo.InvariantCulture, out quality))
                    {
                        quality = Math.Max(Math.Min(quality, 100), 1);
                        this.SetTeaserImageQuality(quality);
                    }
                }
                if (null != this.txtDetailImageFolder)
                {
                    this.SetDetailImageFolder(this.txtDetailImageFolder.Text);
                }
                int prevDetailWidth = this.GetMaxDetailImageWidth();
                int prevDetailHeight = this.GetMaxDetailImageHeight();
                int newDetailWidth = prevDetailWidth;
                int newDetailHeight = prevDetailHeight;
                if (null != this.txtMaxDetailImageWidth)
                {
                    int width;
                    if (int.TryParse(this.txtMaxDetailImageWidth.Text, NumberStyles.Integer,
                                     CultureInfo.InvariantCulture, out width))
                    {
                        this.SetMaxDetailImageWidth(width);
                        newDetailWidth = width;
                    }
                }
                if (null != this.txtMaxDetailImageHeight)
                {
                    int height;
                    if (int.TryParse(this.txtMaxDetailImageHeight.Text, NumberStyles.Integer,
                                     CultureInfo.InvariantCulture, out height))
                    {
                        this.SetMaxDetailImageHeight(height);
                        newDetailHeight = height;
                    }
                }
                if (null != this.txtDetailImageMatte)
                {
                    try
                    {
                        ColorTranslator.FromHtml(this.txtDetailImageMatte.Text);
                        this.SetDetailImageMatte(this.txtDetailImageMatte.Text);
                    }
                    catch (Exception e)
                    {
                        Exceptions.LogException(e);
                    }
                }
                if (null != this.txtDetailImageQuality)
                {
                    long quality;
                    if (long.TryParse(this.txtDetailImageQuality.Text, NumberStyles.Integer,
                                      CultureInfo.InvariantCulture, out quality))
                    {
                        quality = Math.Max(Math.Min(quality, 100), 1);
                        this.SetDetailImageQuality(quality);
                    }
                }
                if (null != this.txtMaxCurrentItems)
                {
                    int maxCur;
                    if (int.TryParse(this.txtMaxCurrentItems.Text, NumberStyles.None, CultureInfo.CurrentUICulture,
                                     out maxCur))
                    {
                        this.SetMaxCurrentItems(maxCur);
                    }
                }
                if (null != this.chkUseDetailImageForTeaserDefault)
                {
                    this.SetUseDetailImageForTeaserDefault(this.chkUseDetailImageForTeaserDefault.Checked);
                }
                if (null != this.chkShowDisabledLanguages)
                {
                    this.SetShowDisabledLanguages(this.chkShowDisabledLanguages.Checked);
                }
                if (null != this.txtMaxImagesToUse)
                {
                    int maxImagesToUse;
                    if (int.TryParse(this.txtMaxImagesToUse.Text, NumberStyles.None, CultureInfo.CurrentUICulture, out maxImagesToUse))
                    {
                        this.SetMaxImagesToUse(maxImagesToUse);
                    }
                }

                //refresh cache
                ModuleController.SynchronizeModule(this.ModuleId);

                bool resizeTeaser = (newTeaserWidth > 0
                                    && (prevTeaserWidth <= 0 || prevTeaserWidth > newTeaserWidth))
                                    || (newTeaserHeight > 0
                                    && (prevTeaserHeight <= 0 || prevTeaserHeight > newTeaserHeight));
                if (resizeTeaser && null != this.chkResizeTeaserImages && this.chkResizeTeaserImages.Checked)
                {
                    this.Settings[SettingsHelper.KeyMaxTeaserImageWidth] = newTeaserWidth.ToString(CultureInfo.InvariantCulture);
                    this.Settings[SettingsHelper.KeyMaxTeaserImageHeight] = newTeaserHeight.ToString(CultureInfo.InvariantCulture);
                    this.Controller.ResizeTeaserImages();
                }
                bool resizeDetail = (newDetailWidth > 0
                                    && (prevDetailWidth <= 0 || prevDetailWidth > newDetailWidth))
                                    || (newDetailHeight > 0
                                    && (prevDetailHeight <= 0 || prevDetailHeight > newDetailHeight));
                if (resizeDetail && null != this.chkResizeDetailImages && this.chkResizeDetailImages.Checked)
                {
                    this.Settings[SettingsHelper.KeyMaxDetailImageWidth] = newDetailWidth.ToString(CultureInfo.InvariantCulture);
                    this.Settings[SettingsHelper.KeyMaxDetailImageHeight] = newDetailHeight.ToString(CultureInfo.InvariantCulture);
                    this.Controller.ResizeDetailImages();
                }
            }
            catch (Exception exc) //Module failed to load
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }

        /// <summary>
        /// Gets the localized string for the given key.
        /// </summary>
        /// <param name="key">The key for which to find the localized string.</param>
        /// <returns>The localized string for the given key.</returns>
        protected string GetString(string key)
        {
            return Localization.GetString(key, this.LocalResourceFile);
        }

        protected string GetString(string key, string defaultText)
        {
            string localizedResource = this.GetString(key);
            if (String.IsNullOrEmpty(localizedResource))
            {
                return defaultText;
            }
            return localizedResource;
        }

        protected bool HasWriteAccess(string folderPath)
        {
            string folder = EnsureTrailingSlash(EnsureTrailingSlash(folderPath).Substring(this.PortalSettings.HomeDirectoryMapPath.Length).Replace(
                '\\', '/'));
            if (folder.Equals("/"))
            {
                folder = String.Empty;
            }
            string roles = FileSystemUtils.GetRoles(folder, this.PortalSettings.PortalId, "WRITE");
            return PortalSecurity.IsInRoles(roles);
        }

        private void CreateFolder(string parentPath, string name)
        {
            if (!Directory.Exists(parentPath))
            {
                int index = parentPath.LastIndexOfAny(new[] {'/', '\\'});
                if (index > 0)
                {
                    CreateFolder(parentPath.Substring(0, index), parentPath.Substring(index + 1));
                }
                else
                {
                    throw new ArgumentException("Path does not exist.", "parentPath");
                }
            }
            if (!Directory.Exists(Path.Combine(parentPath, name)) && this.HasWriteAccess(parentPath))
            {
                FileSystemUtils.AddFolder(this.PortalSettings, parentPath, name);
                string parentFolder = EnsureTrailingSlash(EnsureTrailingSlash(parentPath).Substring(this.PortalSettings.HomeDirectoryMapPath.Length));
                string newFolder = EnsureTrailingSlash(parentFolder + name);
                FolderInfo folder = new FolderController().GetFolder(this.PortalSettings.PortalId, newFolder, false);
                FolderPermissionController fpc = new FolderPermissionController();
                FolderPermissionCollection folderPermissions = fpc.GetFolderPermissionsCollectionByFolderPath(this.PortalSettings.PortalId, parentFolder);
                foreach (FolderPermissionInfo folderPermissionInfo in folderPermissions)
                {
                    FileSystemUtils.SetFolderPermission(this.PortalSettings.PortalId, folder.FolderID, folderPermissionInfo.PermissionID, folderPermissionInfo.RoleID, newFolder);
                }
            }
            else
            {
                throw new SecurityException("You do not have write permissions for this location.");
            }
        }

        protected void CreateFolder(string folderName)
        {
            string folderUrl = this.PortalSettings.HomeDirectory + this.MakeFolderUrl(folderName);
            string path = Server.MapPath(folderUrl);
            if (!Directory.Exists(path))
            {
                int index = path.LastIndexOfAny(new[] { '/', '\\' });
                if (index > 0)
                {
                    CreateFolder(path.Substring(0, index), path.Substring(index + 1));
                }
                else
                {
                    throw new ArgumentException("Path does not exist.", "folderName");
                }
            }
        }

        protected string MakeFolderUrl(string url)
        {
            return this.Controller.MakeFolderUrl(url);
        }

        #endregion
    }
}